package com.vivek.guess.what.calculation;

import static com.vivz.guess.what.util.GuessWhatUtil.getDifferenceAgainstGuess;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;

import com.vivz.guess.what.type.Position;
import com.vivz.guess.what.vo.Clue;
import com.vivz.guess.what.vo.Guess;

/**
 * <pre>
 * 2. Check for the definite insiders with their definite positions
 * 
 * Check all the guessed words' weights that match the regex : [x]+ against the zero weights.
 * 
 * Use case #1: you have Xs = valid diff betn 0-weight word and guess-word
 * KING ----
 * WIND XX
 * .IN. intersection
 * W..D valid diff (Here you know for sure that W & D are definitely at 1st and 4th postions)
 * 
 * Use case #2: you have Xs < diff betn 0-weight word and guess-word
 * KING ----
 * WILD XX
 * .I.. intersection
 * W.LD valid diff (Here you know that 2 of W, L & D are definitely at their right places and CANNOT be anywhere else)
 * 
 * Use case #3: you have Xs > diff betn 0-weight word and guess-word [NOT POSSIBLE]
 * (Possible when the opponent is a human and has probably given a wrong weighted clue)
 * KING ----
 * RING XX
 * .IN. intersection
 * R... valid diff (Here you know for sure that there was a wrong clue entered)
 * 
 * 
 * Rough text:
 * 
 * In prob map the chars with more than one position probabilities make to the possible insiders group,
 * the ones with only one position make to the definite insiders (however there is one sitiuation use case#2 where this could be wrong)
 * </pre>
 */
public class ZeroPlusXCalculation extends AbstractCalculation {

	@Override
	public void calculate(final List<Guess> guesses, final Map<Character, Set<Position>> probabilityMap) {

		if (isInputValid(guesses, probabilityMap)) {

			for (final Guess zeroWtGuess : guesses) { // for every guess with ----
				final Clue zero = zeroWtGuess.getClue();
				if (zero.hasDash()) {

					for (final Guess g : guesses) { // compare a guess with [x]+ clue

						final Clue clue = g.getClue();
						if (!clue.hasDots() && clue.hasCrosses()) {
							final Map<Character, Position> difference = getDifferenceAgainstGuess(g, zeroWtGuess);

							if (difference.isEmpty()) {
								// This is one of the possibilities in the Use case #3 - boo hoo
							} else {
								final int diff = difference.size();
								final int countX = clue.getCountX();

								if (diff == countX) {
									// This is the Use case #1
									for (final Entry<Character, Position> entry : difference.entrySet()) {
										final Character key = entry.getKey();
										final Position value = entry.getValue();

										// This should not be a true singleton as the only value may be eligible for
										// removal
										final Set<Position> singleton = new TreeSet<Position>();
										singleton.add(value);
										probabilityMap.put(key, singleton);

										// DEFINITE_INSIDERS.add(key);
										value.setConfirmed(true);
									}

								} else if (diff > countX) {
									// This is the Use case #2
									for (final Entry<Character, Position> entry : difference.entrySet()) {
										final Character key = entry.getKey();
										final Position value = entry.getValue();

										// This should not be a true singleton as the only value may be eligible for
										// removal
										final Set<Position> singleton = new TreeSet<Position>();
										singleton.add(value);
										probabilityMap.put(key, singleton);
										// PROBABLE_INSIDERS.add(key);
									}
								} else {
									// This is one of the possibilities in the Use case #3 - boo hoo
								}
							}
						}
					}
				}

			}
			removeEmptyPositionSets(probabilityMap);
		}
	}

}
